using System;
using System.Collections.Generic;
using System.Text;
using Adoor.Object.Domain;
using Adoor.Object.Query;

//design time
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Drawing.Design;
using System.Collections;

namespace Adoor.Object.Domain
{
    /// <summary>
    /// List of Domain Group : <see cref="LinkedDomainGroup"/>
    /// </summary>
    [Serializable, DefaultProperty("Groups")
    //,Editor(typeof(EditorTest),typeof(UITypeEditor))
    ] //Editor("Adoor.VSDesigner.CollectionEditor.LinkedDomainCollectionEditor, Adoor.VSDesigner", typeof(UITypeEditor))]
    public class LinkedDomainCollection : CollectionBase , IList<LinkedDomainGroup>, ICollection<LinkedDomainGroup>, IEnumerable<LinkedDomainGroup>, ICustomTypeDescriptor  
    {
        private Adoor.Collections.Generic.List<LinkedDomainGroup> m_innerList = new Adoor.Collections.Generic.List<LinkedDomainGroup>();

        //[System.ComponentModel.Browsable(false),
        [TypeConverter(typeof(ExpandableObjectConverter)),
        System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
        public Adoor.Collections.Generic.List<LinkedDomainGroup> Groups
        {
            get { return m_innerList; }
        }



        //protected static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public LinkedDomainCollection()
        {
            m_innerList.CollectionChanged += new Adoor.Collections.Generic.CollectionChangeEventHandler<LinkedDomainGroup>(m_innerList_CollectionChanged);
            crossLinkedDomainGroupRemoteSource = new CrossLinkedDomainGroupRemoteSource(this);

        }

        void m_innerList_CollectionChanged(object sender, Adoor.Collections.Generic.CollectionChangeEventArgs<LinkedDomainGroup> e)
        {
            if (e.Action == Adoor.Collections.Generic.CollectionChangeAction.Add)
            {
                e.Element.ObjectResolver = this.ObjectResolver;
            }
        }


        private CrossLinkedDomainGroupRemoteSource crossLinkedDomainGroupRemoteSource;

        public CrossLinkedDomainGroupRemoteSource CrossLinkedDomainGroupRemoteSource
        {
            get { return crossLinkedDomainGroupRemoteSource; }
        }

        public IObjectResolver objectResolver;

        
        public IObjectResolver ObjectResolver
        {
            get
            {
                return objectResolver;
            }
            set
            {
                if (value != this.objectResolver)
                {
                    objectResolver = value;
                    foreach (LinkedDomainGroup group in this.Groups)
                        group.objectResolver = this.objectResolver; 
                }
            }
        }

        public ObjectDomain FindDomainForType(Type type)
        {
            EntityData ed = FindEntityDataForType(type);
            if (ed == null)
                throw new EntityDataNotFoundException("EntityData not found for type " + type.Name);
            return ed.Domain;
        }

        public EntityData FindEntityDataForType(Type type)
        {
            foreach (LinkedDomainGroup domainGroup in this)
            {
                EntityData ed = domainGroup.FindEntityDataForType(type);
                if (ed != null)
                    return ed;
            }
            return null;
        }

        public ObjectQuery ParseQuery(string text)
        {
            foreach (ObjectDomain domain in this.GetAllDomains)
                domain.Build();
            //TODO: ObjectQuery is not linked to a domain yet
            Object.Query.ObjectQuery query = new ObjectQuery(this.objectResolver, text);
            //query.Path = ScanPath.Parse(this.objectResolver, text);
            return query;
        }

        [Browsable(false)]
        public ICollection<ObjectDomain> GetAllDomains
        {
            get
            {
                List<ObjectDomain> domains = new List<ObjectDomain>();
                foreach (LinkedDomainGroup domainGroup in this)
                {
                    domains.AddRange(domainGroup.FlattenedDomains);
                }
                return domains;
            }
        }

       
        /// <summary>
        /// Returns the <see cref="Adoor.Object.Domain.LinkedDomainGroup"/>LinkedDomainGroup holding the domain for this entity type
        /// </summary>
        /// <param name="type">The entity type to search for</param>
        /// <returns></returns>
        public LinkedDomainGroup this[Type type]
        {
            get
            {
                foreach (LinkedDomainGroup domainGroup in this)
                {
                    EntityData ed = domainGroup.FindEntityDataForType(type);
                    if (ed != null)
                        return domainGroup;
                }
                return null;
            }
        }


        #region IList<LinkedDomainGroup> Members

        public int IndexOf(LinkedDomainGroup item)
        {
            return m_innerList.IndexOf(item);
        }

        public void Insert(int index, LinkedDomainGroup item)
        {
            m_innerList.Insert(index, item); 
        }

        public void RemoveAt(int index)
        {
            m_innerList.RemoveAt(index); 
        }

        public LinkedDomainGroup this[int index]
        {
            get
            {
                return m_innerList[index]; 
            }
            set
            {
                m_innerList[index] = value;
            }
        }

        #endregion

        #region ICollection<LinkedDomainGroup> Members

        public void Add(LinkedDomainGroup item)
        {
            m_innerList.Add(item);
            if (this.objectResolver != null)
                item.objectResolver = this.objectResolver; 
        }

        public void Clear()
        {
            m_innerList.Clear();
        }

        public bool Contains(LinkedDomainGroup item)
        {
            return m_innerList.Contains(item);
        }

        public void CopyTo(LinkedDomainGroup[] array, int arrayIndex)
        {
            m_innerList.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return m_innerList.Count; }
        }

        public bool IsReadOnly
        {
            get { return m_innerList.IsReadOnly; }
        }

        public bool Remove(LinkedDomainGroup item)
        {
            return m_innerList.Remove(item);
        }

        #endregion

        #region IEnumerable<LinkedDomainGroup> Members

        public IEnumerator<LinkedDomainGroup> GetEnumerator()
        {
            return m_innerList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return (m_innerList as System.Collections.IEnumerable).GetEnumerator(); ;
        }

        #endregion

        #region ICustomTypeDescriptor Members

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this, true);
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return TypeDescriptor.GetProperties(this, attributes, true);
        }

        public PropertyDescriptorCollection GetProperties()
        {
            return TypeDescriptor.GetProperties(this, true);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion
    }
}
